package com.vision.util.http.util;

import com.google.common.collect.Maps;
import com.vision.util.http.AbsHttpFactory;
import com.vision.util.http.exception.RequestFailedException;
import org.apache.commons.io.IOUtils;
import org.apache.http.Header;
import org.apache.http.NameValuePair;
import org.apache.http.client.CookieStore;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 项目名称：vision
 * 类名称： HttpRequestDao
 * 类描述：
 * 创建人：zc
 * 创建时间：2017-01-19 18:50
 * 修改人：
 * 修改时间：
 * 修改备注：
 *
 * @version 1.0
 */
public class HttpRequestDao {

    private static final Logger logger = LoggerFactory.getLogger(HttpRequestDao.class);

    private CloseableHttpClient httpClient;

    private RequestConfig requestConfig;

    private HttpClientContext httpClientContext;

    private Header[] responseHeaders;

    public HttpRequestDao(AbsHttpFactory factory) {
        Assert.notNull(factory);
        this.httpClient = factory.getHttpClient();
        this.requestConfig = factory.getRequestConfig();
        this.httpClientContext = factory.getHttpClientContext();
    }

    public String getWebPage(String url) throws RequestFailedException {
        HttpGet request = new HttpGet(url);
        return getWebPage(request, "utf-8", false);
    }

    public String getWebPage(String url, Header... headers) throws RequestFailedException {
        HttpGet request = new HttpGet(url);
        return getWebPage(request, "utf-8", false, headers);
    }

    public String postRequest(String postUrl, Map<String, String> params) throws RequestFailedException {
        HttpPost post = new HttpPost(postUrl);
        setHttpPostParams(post, params);
        return getWebPage(post, "utf-8", false);
    }

    public String postRequest(String postUrl, Map<String, String> params, Header... headers) throws RequestFailedException {
        HttpPost post = new HttpPost(postUrl);
        setHttpPostParams(post, params);
        return getWebPage(post, "utf-8", false, headers);
    }

    public Map<String, Object> postResponse(String postUrl, Map<String, String> params, Header... headers) throws RequestFailedException, IOException {
        Map<String, Object> map = Maps.newHashMap();
        HttpPost post = new HttpPost(postUrl);
        setHttpPostParams(post, params);
        map.put("response", getResponse(post, headers));
        map.put("request", post);
        return map;
    }

    public String postRequestJson(String postUrl, String params, String contentEncoding) throws RequestFailedException {
        HttpPost post = new HttpPost(postUrl);
        setHttpPostParamsJson(post, params, contentEncoding);
        return getWebPage(post, "utf-8", false);
    }

    public String postRequestJson(String postUrl, String params, String contentEncoding, Header... headers) throws RequestFailedException {
        HttpPost post = new HttpPost(postUrl);
        setHttpPostParamsJson(post, params, contentEncoding);
        return getWebPage(post, "utf-8", false, headers);
    }

    /**
     * @param encoding       字符编码
     * @param isPrintConsole 是否打印到控制台
     * @return 网页内容
     */
    public String getWebPage(HttpRequestBase request
            , String encoding
            , boolean isPrintConsole, Header... headers) throws RequestFailedException {
        try (CloseableHttpResponse response = getResponse(request, headers); InputStream content = response.getEntity().getContent();
             BufferedReader rd = new BufferedReader(
                     new InputStreamReader(content, encoding))) {
            logger.info("status:" + response.getStatusLine().getStatusCode());
            StringBuilder webPage = new StringBuilder();
            String line;
            while ((line = rd.readLine()) != null) {
                webPage.append(line);
                if (isPrintConsole) {
                    logger.info(line);
                }
            }
            rd.close();
            request.releaseConnection();
            responseHeaders = response.getAllHeaders();
            return webPage.toString();
        } catch (Exception e) {
            throw new RequestFailedException("获取数据异常 url:" + request.getURI() + " \n 原因 ", e);
        }
    }

    public String getWebPageByResponse(CloseableHttpResponse response, HttpRequestBase request, String encoding) {
        BufferedReader rd;
        StringBuilder webPage = new StringBuilder();
        try {
            rd = new BufferedReader(
                    new InputStreamReader(response.getEntity().getContent(), encoding == null ? "UTF-8" : encoding));
            String line;
            while ((line = rd.readLine()) != null) {
                webPage.append(line);
            }
        } catch (IOException e) {
            logger.error("读取数据异常:url:{}", request.getURI(), e);
        }
        request.releaseConnection();
        return webPage.toString();
    }

    public CloseableHttpResponse getResponse(HttpRequestBase request, Header... headers) throws IOException {
        request.setConfig(requestConfig);
        if (headers != null && headers.length > 0) {
            request.setHeaders(headers);
        }
        return httpClient.execute(request, httpClientContext);
    }

    public CloseableHttpResponse getResponse(String url) throws IOException {
        HttpGet request = new HttpGet(url);
        return getResponse(request);
    }

    /**
     * 设置request请求参数
     *
     * @param request
     * @param params
     */
    public void setHttpPostParams(HttpPost request, Map<String, String> params) {
        List<NameValuePair> formParams = new ArrayList<NameValuePair>();
        for (String key : params.keySet()) {
            formParams.add(new BasicNameValuePair(key, params.get(key)));
        }
        UrlEncodedFormEntity entity = null;
        try {
            // entity.setContentType("application/json");
            entity = new UrlEncodedFormEntity(formParams, "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        request.setEntity(entity);
    }


    /**
     * 设置request请求参数
     *
     * @param request
     * @param params
     */
    public void setHttpPostParamsJson(HttpPost request, String params, String contentEncoding) {
        StringEntity entity = null;
        try {
            entity = new StringEntity(params);
            entity.setContentEncoding(contentEncoding);
            entity.setContentType("application/json");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        request.setEntity(entity);
    }

    /**
     * 下载图片
     *
     * @param fileURL       文件地址
     * @param path          保存路径
     * @param saveFileName  文件名，包括后缀名
     * @param isReplaceFile 若存在文件时，是否还需要下载文件
     */
    public void downloadFile(String fileURL
            , String path
            , String saveFileName
            , Boolean isReplaceFile) {
        try {
            CloseableHttpResponse response = getResponse(fileURL);
            logger.info("status:" + response.getStatusLine().getStatusCode());
            File file = new File(path);
            //如果文件夹不存在则创建
            if (!file.exists() && !file.isDirectory()) {
                file.mkdirs();
            } else {
                logger.info("//目录存在");
            }
            file = new File(path + saveFileName);
            if (!file.exists() || isReplaceFile) {
                //如果文件不存在，则下载
                try (OutputStream os = new FileOutputStream(file); InputStream is = response.getEntity().getContent()) {
                    byte[] buff = new byte[(int) response.getEntity().getContentLength()];
                    while (true) {
                        int readed = is.read(buff);
                        if (readed == -1) {
                            break;
                        }
                        byte[] temp = new byte[readed];
                        System.arraycopy(buff, 0, temp, 0, readed);
                        os.write(temp);
                        logger.info("文件下载中....");
                    }
                    is.close();
                    os.close();
                    logger.info(fileURL + "--文件成功下载至" + path + saveFileName);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else {
                logger.info(path);
                logger.info("该文件存在！");
            }
            response.close();
        } catch (IllegalArgumentException e) {
            logger.info("连接超时...");
        } catch (Exception e1) {
            e1.printStackTrace();
        }
    }

    /**
     * 输出Cookies
     *
     * @param cs
     */
    public static void getCookies(CookieStore cs) {
        List<Cookie> cookies = cs.getCookies();
        if (cookies == null) {
            logger.info("该CookiesStore无Cookie");
        } else {
            for (int i = 0; i < cookies.size(); i++) {
                logger.info("cookie：" + cookies.get(i).getName() + ":" + cookies.get(i).getValue()
                        + "----过期时间" + cookies.get(i).getExpiryDate()
                        + "----Comment" + cookies.get(i).getComment()
                        + "----CommentURL" + cookies.get(i).getCommentURL()
                        + "----domain" + cookies.get(i).getDomain()
                        + "----ports" + Arrays.toString(cookies.get(i).getPorts())
                );
            }
        }
    }

    public Header[] getResponseHeaders() {
        return responseHeaders;
    }

    /**
     * InputStream转换为String
     *
     * @param is
     * @param encoding
     * @return
     * @throws Exception
     */
    public static String isToString(InputStream is, String encoding) throws Exception {
        StringWriter writer = new StringWriter();
        IOUtils.copy(is, writer, encoding);
        return writer.toString();
    }

    public HttpClientContext getHttpClientContext() {
        return httpClientContext;
    }
}
